#include <stdio.h>
#include <stdlib.h>


#define BLOCK_SIZE 512
#define MBR_BLOCKS 1 	
#define I_NODE_SIZE 32
#define DATA_INDEX_OFFSET 18
#define INDEX_SIZE 2
#define FILE_ITEM_SIZE 16
#define FILE_NAME_SIZE 14
#define TYPE_DIR 1
#define TYPE_NORMAL_FILE 0
#define I_START_OFFSET 19
#define DATA_START_OFFSET 23
#define NUM_OF_FILE_ITEM_PER_BLOCK 32
#define NUM_DIRECT_INDEX 4
#define NUM_1_INDIRECT_INDEX 2

int compare(char *filename1,char *filename2);
long get_file_size(char *filename);

int main(){
	unsigned short i_start;
	unsigned short b_start;
	
	FILE *fpr = fopen("lessos.img","rb");
	if(fpr==NULL){
		printf("%s\n","Open file failure!");
		exit(0);
	}

	int meta_block_offset = MBR_BLOCKS * BLOCK_SIZE;
	fseek(fpr,meta_block_offset + I_START_OFFSET,SEEK_SET);
	fread(&i_start,sizeof(short),1,fpr);
	printf("i_node start block %u\n",i_start);

	fseek(fpr,meta_block_offset + DATA_START_OFFSET,SEEK_SET);
	fread(&b_start,sizeof(short),1,fpr);
	printf("data_block start block %u\n",b_start);

	int root_dir_offset = (b_start + MBR_BLOCKS) * BLOCK_SIZE;
	unsigned char filename[14];
	unsigned short file_node;
        int i = 0;
	for(i=0;i<NUM_OF_FILE_ITEM_PER_BLOCK;i++){
		fseek(fpr,root_dir_offset,SEEK_SET);
		fread(filename,sizeof(char),14,fpr);
		if(compare(filename,"loader")==0){
			fseek(fpr,root_dir_offset + FILE_NAME_SIZE,SEEK_SET);
			fread(&file_node,sizeof(short),1,fpr);
			printf("filename %s , file_node %u \n", filename,file_node);
			break;
		}
	        root_dir_offset += FILE_ITEM_SIZE;
	}
	
	int data_block_offset = (i_start + MBR_BLOCKS) * BLOCK_SIZE + file_node * I_NODE_SIZE + DATA_INDEX_OFFSET;

	FILE *readed_fpr = fopen("data","w+");
	long loader_size = get_file_size("loader");
	int LENGTH_INDEX_RECORD = 2;
	// read direct index block 	
	int direct_num = NUM_DIRECT_INDEX;
	if(loader_size/BLOCK_SIZE<NUM_DIRECT_INDEX){
		direct_num = loader_size/BLOCK_SIZE;
	}
	for(i=0;i<direct_num;i++){
		unsigned char data[BLOCK_SIZE];
		unsigned short data_block;
		fseek(fpr,data_block_offset,SEEK_SET);
		fread(&data_block,sizeof(short),1,fpr);
		if(data_block!=0){
			int data_offset = (data_block + MBR_BLOCKS) * BLOCK_SIZE;
			fseek(fpr,data_offset,SEEK_SET);
			fread(data,sizeof(char),BLOCK_SIZE,fpr);
			fwrite(data,sizeof(char),BLOCK_SIZE,readed_fpr);
		}
		data_block_offset += LENGTH_INDEX_RECORD;
	}
	
	if(direct_num<NUM_DIRECT_INDEX){
        	fclose(readed_fpr);
		compare_file("data","loader");
	}

	// read 1 indirect block
	int left_size = loader_size - NUM_DIRECT_INDEX * BLOCK_SIZE;
	int indirect_node_offset = data_block_offset;
	int indirect_node_num = 2;
	for(i=0;i<indirect_node_num;i++){
		unsigned short indirect_node_block;
		fseek(fpr,indirect_node_offset,SEEK_SET);
		fread(&indirect_node_block,sizeof(short),1,fpr);
		if(indirect_node_block!=0){
			int j;
			int indirect_data_offset = (indirect_node_block + MBR_BLOCKS) * BLOCK_SIZE;
			for(j=0;j<256;j++){
				unsigned char data[BLOCK_SIZE];
				unsigned short indirect_data_block;
				fseek(fpr,indirect_data_offset,SEEK_SET);
				fread(&indirect_data_block,sizeof(short),1,fpr);
				if(indirect_data_block!=0){
					int data_offset = (indirect_data_block + MBR_BLOCKS) * BLOCK_SIZE;
					fseek(fpr,data_offset,SEEK_SET);
					if(left_size>=BLOCK_SIZE){
						unsigned char data[BLOCK_SIZE];
						fread(data,sizeof(char),BLOCK_SIZE,fpr);
						fwrite(data,sizeof(char),BLOCK_SIZE,readed_fpr);
					}else{
						unsigned char data[left_size];
						fread(data,sizeof(char),left_size,fpr);
						fwrite(data,sizeof(char),left_size,readed_fpr);

					}
					left_size -= BLOCK_SIZE;
				}
				indirect_data_offset += INDEX_SIZE;
			}

		}
		indirect_node_offset += INDEX_SIZE;
	}
        fclose(readed_fpr);
	compare_file("data","loader");

	fclose(fpr);
}

int compare(char *filename1, char *filename2){
	while(*filename2!='\0'){
		if(*filename1++ != *filename2++){
			return -1;
		}
	}
	return 0;
}

long get_file_size(char *filename){
	FILE *fpr = fopen(filename,"rb");
	if(fpr==NULL){
		return -1;
	}
	fseek(fpr,0L,SEEK_END);
	int size = ftell(fpr);
	fclose(fpr);
	return size;
}

int compare_file(char *file1, char *file2){
	FILE *fpr1 = fopen(file1,"rb");
	FILE *fpr2 = fopen(file2,"rb");
	if(fpr1==NULL || fpr2==NULL){
		printf("Oops,open file failure!");
		exit(0);
	}

	long file1size = get_file_size(file1);
	long file2size = get_file_size(file2);
	printf("file1size: %lu  file2size: %lu",file1size,file2size);
	if(file1size<file2size || file1size==-1 || file2size==-1){
		printf("Oops,the loader you have readed is not right!");
		exit(0);
	}
	
	int i;
	for(i=0;i<file2size;i++){
		char a,b;
		fseek(fpr1,i,SEEK_SET);
		fread(&a,sizeof(char),1,fpr1);
		
		fseek(fpr2,i,SEEK_SET);
		fread(&b,sizeof(char),1,fpr2);
		if(a!=b){
			printf("Oops,the loader you have readed is not right!");
			exit(0);
		}
	}
	printf("Congratulations! You have successfully readed loader!\n");
        exit(0);		
}
